package com.sztx.pay.center.worker.quartz;

import java.util.Date;
import java.util.List;

import org.mortbay.log.Log;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.Constance.CallBackOrderState;
import com.sztx.pay.center.common.util.Constance.CardActType;
import com.sztx.pay.center.common.util.Constance.DistributeType;
import com.sztx.pay.center.common.util.Constance.PayFlowState;
import com.sztx.pay.center.common.util.Constance.TradeOrderType;
import com.sztx.pay.center.common.util.Constance.UserActType;
import com.sztx.pay.center.common.util.Constance.WithDrawType;
import com.sztx.pay.center.common.util.Constance.WithdrawState;
import com.sztx.pay.center.common.util.JFUtils;
import com.sztx.pay.center.core.service.AccountFlowService;
import com.sztx.pay.center.core.service.AccountService;
import com.sztx.pay.center.core.service.ActService;
import com.sztx.pay.center.core.service.BillnoService;
import com.sztx.pay.center.core.service.CallBackService;
import com.sztx.pay.center.core.service.OrderMappingService;
import com.sztx.pay.center.core.service.PayCoreService;
import com.sztx.pay.center.core.service.SettleService;
import com.sztx.pay.center.core.service.UserInfoService;
import com.sztx.pay.center.core.service.bean.CallBackInfo;
import com.sztx.pay.center.core.service.bean.PayCoreDistribute;
import com.sztx.pay.center.core.service.bean.PayCoreResult;
import com.sztx.pay.center.core.service.bean.PayCoreTransferReq;
import com.sztx.pay.center.dataaccess.dao.mysql.GatewaySwiftCodeBankIdMappingMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderWithdrawMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.UserBindCardMysqlDAO;
import com.sztx.pay.center.dataaccess.domain.OrderWithdrawDO;
import com.sztx.pay.center.dataaccess.domain.UserActDO;
import com.sztx.pay.center.dataaccess.domain.UserBindCardDO;
import com.sztx.pay.center.dataaccess.domain.UserInfoDO;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.common.util.StringUtil;
import com.sztx.se.core.quartz.job.BaseJob;
@Component("withdrawJob")
public class WithdrawJob extends BaseJob{
	@Autowired
	OrderWithdrawMysqlDAO orderWithdrawMysqlDAO;
	@Autowired
	GatewaySwiftCodeBankIdMappingMysqlDAO gatewaySwiftCodeBankIdMappingMysqlDAO;
	@Autowired
	AccountService accountService;
	@Autowired
	BillnoService billnoService;
	@Autowired
	PayCoreService payCoreService;
	@Autowired
	SettleService settleService;
	@Autowired
	CallBackService callBackService;
	@Autowired
	OrderMappingService orderMappingService;
//	@Autowired
//	private LockRedisDAO lockRedisDAO;
//	@Autowired
//	AccountFlowService accountFlowService;
	@Autowired
	private UserBindCardMysqlDAO userBindCardMysqlDAO;
	@Autowired
	private ActService actService;
	@Autowired
	private UserInfoService userInfoService;
	@Override
	public Object executeJob(JobExecutionContext context)
			throws JobExecutionException {
		Log.info("======================WithdrawJob start====================");
		List<OrderWithdrawDO> orderWithdrawDOs = getwithdrawList();
		if(orderWithdrawDOs == null || orderWithdrawDOs.size() < 1){
			Log.info("WithdrawJob have no order to withdraw ");
			return null;
		}
		
		for (int i = 0; i < orderWithdrawDOs.size(); i++) {
			OrderWithdrawDO orderWithdrawDO = orderWithdrawDOs.get(i);
			String referOrderId = orderWithdrawDO.getWithdrawOrderId();
			Byte orderStatus = orderWithdrawDO.getOrderStatus();
			WithdrawState withdrawState = WithdrawState.valueOf(orderStatus);
			if(withdrawState != WithdrawState.WITHDRAW_STATUS_INIT){
				continue;
			}
//			try {
//				accountService.findUserBindInfo(orderWithdrawDO.getBindNo(), orderWithdrawDO.getPayerUserId(), null);
//			} catch (Exception e) {
//				Log.warn("bindNo查询提现银行卡异常,orderWithdrawDO:"+JSONObject.toJSONString(orderWithdrawDO));
//				/**
//				 * 绑定银行卡异常    执行退款
//				 */
//				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_FAIL.getCode());
//				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_FAIL.getCode(),"提现银行卡状态异常");
//			
//				orderFailRefund(orderWithdrawDO);
//				
//				continue;
//			}
			
			
			Log.info("WithdrawJob resolve a orderid:"+referOrderId);
			updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_IN);
			WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
			PayCoreResult result = new PayCoreResult();
			try {
				if(withdrawType == WithDrawType.WITHDRAW_REBATE){
					//先进行佣金账户转入用户账户余额
					b2cTansfer(orderWithdrawDO);
				}
				result = innerWithDraw(referOrderId);
			} catch (Exception e) {
				Log.warn(e);
			}
			
			
			PayFlowState payFlowState = PayFlowState.valueOf(result.getTradeSataus());
			if(payFlowState == PayFlowState.SUCCESS ){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_SUCCESS);
			}else if(payFlowState == PayFlowState.FAIL){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_FAIL);
				if(withdrawType == WithDrawType.WITHDRAW_REBATE){
					//提现失败进行退款
					c2bRefundTansfer(orderWithdrawDO);
				}
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_FAIL,result.getTradeDesc());
			}else if(payFlowState == PayFlowState.EXCEPTION){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,result.getTradeDesc());
			}else if(payFlowState == null){
				updateWithDrawOrderState(referOrderId, WithdrawState.WITHDRAW_STATUS_EXCEPTION);
				callBack(referOrderId, Constance.WithdrawState.WITHDRAW_STATUS_EXCEPTION,result.getTradeDesc());
			}
			
			
			
		}
		return null;
	}

	private List<OrderWithdrawDO> getwithdrawList(){
		OrderWithdrawDO orderWithdrawDo = new OrderWithdrawDO();
		orderWithdrawDo.setOrderStatus((byte)WithdrawState.WITHDRAW_STATUS_INIT.getCode());
		return orderWithdrawMysqlDAO.findWithDrawOrders(orderWithdrawDo );
	}
	
	private void updateWithDrawOrderState(String withdrawOrderId,WithdrawState state){
		OrderWithdrawDO orderWithdrawDO = new OrderWithdrawDO();
		orderWithdrawDO.setWithdrawOrderId(withdrawOrderId);
		orderWithdrawDO.setOrderStatus((byte) state.getCode());
		orderWithdrawDO.setOrderDesc( state.getDesc());
		orderWithdrawMysqlDAO.update(orderWithdrawDO);	
	}

	UserActDO getPayerActInfo(String payerUserId,String channelId) {
		UserActDO userActDO = null;
		UserInfoDO userInfoDO = userInfoService.findUserInfo(payerUserId);
		Integer userType = userInfoDO.getUserType();
		boolean isJfChannel = JFUtils.isJFChannel(channelId);
		boolean isJfUser = (userType.intValue() & Constance.UserType.AGENT.getCode()) != 0;
		if(isJfChannel){
			//是缴费商用户
			if(!isJfUser){
				throw new BusinessException("该帐号【"+payerUserId+"】暂不支持此交易");
			}
//			userActDO = actService.findUserAct(payerUserId, UserActType.JF);
			userActDO = actService.findValidActInfo(payerUserId, UserActType.JF,true);
		}else{
			//其他类型用户
//			userActDO = actService.findUserAct(payerUserId, UserActType.CASH);
			userActDO = actService.findValidActInfo(payerUserId, UserActType.CASH,true);
		}
		if (userActDO == null) {
			throw new BusinessException(payerUserId+"账户不存在");
		}
		userActDO.setUserType(userType);
		return userActDO;
	}
	
	//代发
	public PayCoreResult innerWithDraw(String referOrderId) {
		OrderWithdrawDO orderWithdrawDO = orderWithdrawMysqlDAO.findById(referOrderId);
		UserBindCardDO payerBindCardInfo = accountService.findUserBindInfo(orderWithdrawDO.getPayerBindNo(), orderWithdrawDO.getPayerUserId(), null);
		UserActDO payerActInfo = getPayerActInfo(orderWithdrawDO.getPayerUserId(), orderWithdrawDO.getPlatChannelId());
		
		WithDrawType withdrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		TradeOrderType tradeOrderType = withdrawType == 
				WithDrawType.WITHDRAW_BERBON ? TradeOrderType.BALANCE_WITHDRAW_ORDER : TradeOrderType.PROFIT_WITHDRAW_ORDER;
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)tradeOrderType.getCode());
		
		PayCoreDistribute payCoreDistribute = new PayCoreDistribute();
		if(withdrawType.equals(WithDrawType.WITHDRAW_REBATE)){
			payCoreDistribute.setPayerActNo(null);
			payCoreDistribute.setPayerUserType(1);
			payCoreDistribute.setPayerActType(UserActType.CASH);
			payCoreDistribute.setPayerUserId(Constance.USER_ID_SZTX);
		}else if(withdrawType.equals(WithDrawType.WITHDRAW_BERBON)){
			payCoreDistribute.setPayerActNo(payerActInfo.getActNo());
			payCoreDistribute.setPayerUserType(payerActInfo.getUserType());
			payCoreDistribute.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
			payCoreDistribute.setPayerUserId(payerActInfo.getUserId());
		}
		
		Integer	cardActType = payerBindCardInfo.getCardActType();
		String	realName = payerBindCardInfo.getRealName();
		String cardProvince = payerBindCardInfo.getCardProvince();
		String cardCity = payerBindCardInfo.getCardCity();
		CardActType paycardActType = null;
		if(cardActType != null){
			paycardActType = CardActType.valueOf(cardActType);
		}
		DistributeType distributeType = null;
		if(payerBindCardInfo.getBindType() == 2){
			distributeType = DistributeType.BANK;
		}else if(payerBindCardInfo.getBindType() == 3){
			distributeType = DistributeType.ALIPAY;
		}
		
		
		payCoreDistribute.setReferOrderId(mappingOrderId);
		payCoreDistribute.setTradeOrderType(tradeOrderType);
		payCoreDistribute.setPayeeUserId(orderWithdrawDO.getPayerUserId());
		payCoreDistribute.setPayeeUserType(payerActInfo.getUserType());
		payCoreDistribute.setPayeeAccountId(payerBindCardInfo.getCardNo());
		payCoreDistribute.setPayeeActType(UserActType.valueOf(payerActInfo.getActType()));
		payCoreDistribute.setAmount(orderWithdrawDO.getWithdrawAmount());
		
		payCoreDistribute.setDistributeType(distributeType);
		payCoreDistribute.setFeeAmount(orderWithdrawDO.getWithdrawFee());
		payCoreDistribute.setOriginOrderNo(orderWithdrawDO.getWithdrawOrderId());
		
		
		
		
		payCoreDistribute.setAttach(orderWithdrawDO.getRemark());
		payCoreDistribute.setRealName(realName);
		payCoreDistribute.setCardActType(paycardActType );
		payCoreDistribute.setCardProvince(cardProvince);
		payCoreDistribute.setCardCity(cardCity);
		
		
		if(cardActType != null && cardActType == CardActType.CARD_ACT_PUBLIC.getValue()){
			String bankId = payerBindCardInfo.getBankId();
			if(StringUtil.isBlank(bankId)){
				String swiftCode = payerBindCardInfo.getSwiftCode();
				if(StringUtil.isNotBlank(swiftCode)){
					bankId = gatewaySwiftCodeBankIdMappingMysqlDAO.getBankIdBySwiftCode(swiftCode, 6);
				}
			}
			payCoreDistribute.setBankId(bankId);
		}
		
		
		PayCoreResult result = payCoreService.distribute(payCoreDistribute , "tradeWithdrawService");
		
		OrderWithdrawDO uporderWithdrawDO = new OrderWithdrawDO();
		uporderWithdrawDO.setWithdrawOrderId(orderWithdrawDO.getWithdrawOrderId());
		uporderWithdrawDO.setPayChannelId(result.getChannelId());
		uporderWithdrawDO.setOrderStatus((byte)WithdrawState.WITHDRAW_ORDER_SUBMIT.getCode());
		uporderWithdrawDO.setOrderDesc(WithdrawState.WITHDRAW_ORDER_SUBMIT.getDesc());
		orderWithdrawMysqlDAO.update(uporderWithdrawDO);	
		
		return result;
	}
	
	
	/**
	 * 
	 * @param orderWithdrawDO
	 */
	private void b2cTansfer(OrderWithdrawDO orderWithdrawDO){
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)TradeOrderType.TRANSFER_ORDER.getCode());
		PayCoreTransferReq req = new PayCoreTransferReq();
		req.setAmount(orderWithdrawDO.getWithdrawAmount());
		req.setFeeAmount(0);
		req.setAttach("返利金转入用户余额");
		req.setOrderId(mappingOrderId);
		req.setOriginOrderId(orderWithdrawDO.getWithdrawOrderId());
		req.setPayerActNo(Constance.ACT_REBATE);
		req.setPayerUserType(1);
		req.setPayerActType(UserActType.CASH);
		req.setPayerUserId(Constance.USER_REBATE);
		UserActDO payerActInfo = getPayerActInfo(orderWithdrawDO.getPayerUserId(), orderWithdrawDO.getPlatChannelId());
		req.setPayeeActNo(payerActInfo.getActNo());
		req.setPayeeUserType(payerActInfo.getUserType());
		req.setPayeeActType(UserActType.valueOf(payerActInfo.getActType()));
		req.setPayeeUserId(payerActInfo.getUserId());
		
		req.setTradeOrderType(TradeOrderType.TRANSFER_ORDER);
		payCoreService.balanceTransfer(req );
		updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_DEBIT_SUCCESS);
	}
	
	/**
	 * 
	 * @param orderWithdrawDO
	 */
	private void c2bRefundTansfer(OrderWithdrawDO orderWithdrawDO){
		String mappingOrderId = orderMappingService.addMappingOrder(orderWithdrawDO.getWithdrawOrderId(), (byte)TradeOrderType.TRANSFER_ORDER.getCode());
		PayCoreTransferReq req = new PayCoreTransferReq();
		req.setAmount(orderWithdrawDO.getWithdrawAmount());
		req.setFeeAmount(0);
		req.setAttach("提现失败,用户余额退回返利金账户");
		req.setOrderId(mappingOrderId);
		req.setOriginOrderId(orderWithdrawDO.getWithdrawOrderId());
		req.setPayeeActNo(Constance.ACT_REBATE);
		req.setPayeeUserType(1);
		req.setPayeeActType(UserActType.CASH);
		req.setPayeeUserId(Constance.USER_REBATE);
		UserActDO payerActInfo = getPayerActInfo(orderWithdrawDO.getPayerUserId(), orderWithdrawDO.getPlatChannelId());
		req.setPayerActNo(payerActInfo.getActNo());
		req.setPayerUserType(payerActInfo.getUserType());
		req.setPayerActType(UserActType.valueOf(payerActInfo.getActType()));
		req.setPayerUserId(payerActInfo.getUserId());
		
		req.setTradeOrderType(TradeOrderType.TRANSFER_ORDER);
		payCoreService.balanceTransfer(req );
		updateWithDrawOrderState(orderWithdrawDO.getWithdrawOrderId(), WithdrawState.WITHDRAW_ORDER_FAIL_REFUND);
	}
	
	//通知业务系统
	private void callBack(String withdrawOrderId,WithdrawState state,String orderDesc){
		Date payTime = new Date();
		OrderWithdrawDO orderWithdrawDO = new OrderWithdrawDO();
		orderWithdrawDO.setWithdrawOrderId(withdrawOrderId);
		orderWithdrawDO.setOrderStatus((byte) state.getCode());
		orderWithdrawDO.setOrderDesc( state.getDesc());
		orderWithdrawDO.setPayTime(payTime);
		orderWithdrawMysqlDAO.update(orderWithdrawDO);
		orderWithdrawDO = orderWithdrawMysqlDAO.findById(withdrawOrderId);
		//通知业务系统
		CallBackOrderState callBackOrderState = null;
		if(state.equals(WithdrawState.WITHDRAW_STATUS_SUCCESS)){
			callBackOrderState = CallBackOrderState.SUCCESS;
		}else if(state.equals(WithdrawState.WITHDRAW_STATUS_FAIL)){
			callBackOrderState = CallBackOrderState.FAIL;
		}else if(state.equals(WithdrawState.WITHDRAW_STATUS_EXCEPTION)){
			callBackOrderState = CallBackOrderState.EXCEPTION;
		}else{
			throw new BusinessException("非法的业务回调，当前订单状态不允许回调！ withdrawState:"+state);
		}
		
		WithDrawType withDrawType = WithDrawType.valueOf(orderWithdrawDO.getWithdrawType());
		TradeOrderType tradeOrderType = null;
		if(withDrawType.equals(WithDrawType.WITHDRAW_BERBON)){
			tradeOrderType = TradeOrderType.BALANCE_WITHDRAW_ORDER;
		}else if(withDrawType.equals(WithDrawType.WITHDRAW_REBATE)){
			tradeOrderType = TradeOrderType.PROFIT_WITHDRAW_ORDER;
		}
		CallBackInfo callBackInfo = new CallBackInfo();
		callBackInfo.setTradeOrderId(withdrawOrderId);
		callBackInfo.setOutOrderId(orderWithdrawDO.getOrderId());
		callBackInfo.setNotfiyUrl(orderWithdrawDO.getNotifyUrl());
		callBackInfo.setReturnUrl(orderWithdrawDO.getReturnUrl());
		callBackInfo.setTotalFee(orderWithdrawDO.getWithdrawFee().intValue());
		callBackInfo.setPayAmount(orderWithdrawDO.getWithdrawAmount().intValue());
		callBackInfo.setAttach(orderWithdrawDO.getRemark());
		callBackInfo.setPayTime(payTime);
		callBackInfo.setTradeCrateTime(orderWithdrawDO.getAddTime());
		callBackInfo.setOrderType(tradeOrderType);
		callBackInfo.setOrderState(callBackOrderState);
		callBackInfo.setOrderDesc(orderDesc);
		callBackService.callBack(callBackInfo );
	}
}
